//
//  Sockaddr+ITSocket.swift
//  QuicDemo
//
//  Created by ellzu gu on 2021/6/29.
//

import Foundation

extension sockaddr: ExtensionCompatible{}
extension sockaddr_storage: ExtensionCompatible {
    public var ex: Extension<sockaddr> {
        return withUnsafePointer(to: self) { (pointer: UnsafePointer<sockaddr_storage>) -> Extension<sockaddr> in
            Extension(UnsafeRawPointer(pointer).assumingMemoryBound(to: sockaddr.self).pointee)
        }
    }
}

extension Extension where Base == sockaddr {
    
    public func toString() -> String {
        return String(format: "%@:%d", ipString(), port())
    }
    
    public func ipString() -> String {
        return withUnsafePointer(to: base) { (pointer: UnsafePointer<sockaddr>) -> String in
            var ipCahr = [CChar](repeating: 0, count: Int(NI_MAXHOST))
            memset(&ipCahr, 0, ipCahr.count)
            guard getnameinfo(pointer, socklen_t(pointer.pointee.sa_len), &ipCahr, socklen_t(ipCahr.count), nil, 0, NI_NUMERICHOST) == 0 else {
                return ""
            }
            let ip: String = String(cString: ipCahr)
            return ip
        }
    }
    
    public func port() -> UInt16 {
        return withUnsafePointer(to: base) { (pointer: UnsafePointer<sockaddr>) -> UInt16 in
            var port: UInt16 = 0
            switch Int32(pointer.pointee.sa_family) {
            case AF_INET:
                let v4Pointer = UnsafeRawPointer(pointer).assumingMemoryBound(to: sockaddr_in.self)
                port = CFSwapInt16(v4Pointer.pointee.sin_port)
                break
            case AF_INET6:
                let v6Pointer = UnsafeRawPointer(pointer).assumingMemoryBound(to: sockaddr_in6.self)
                port = CFSwapInt16(v6Pointer.pointee.sin6_port)
                break
            default:
                port = 0xFFFF
            }
            return port
        }
    }
    
}
